package net.aiion.weave.impl.naming;

import net.aiion.weave.spi.feeding.FeedFactory;
import net.aiion.weave.spi.messaging.MessageCallback;
import net.aiion.weave.spi.messaging.MessageResult;
import net.aiion.weave.spi.messaging.MessageService;
import net.aiion.weave.spi.naming.Context;
import net.aiion.weave.spi.naming.Contextual;
import net.aiion.weave.spi.naming.ConversationContext;
import net.aiion.weave.spi.naming.annotations.ConversationScoped;
import net.aiion.weave.spi.naming.callbacks.FeedDispatchedCallback;
import net.aiion.weave.spi.naming.callbacks.RouteDispatchedCallback;
import net.aiion.weave.spi.routing.Route;
import net.aiion.weave.spi.routing.RouteFactory;
import net.aiion.weave.spi.routing.RouteMessage;

public class ConversationContextImpl extends ContextImpl implements ConversationContext {
    private static final String CONVERSATION_CONTEXT_NAME = ConversationContext.class.getName();

    private RouteFactory routeFactory;

    private MessageService messageService;

    private FeedFactory feedFactory;

    public ConversationContextImpl(final Context parentContext) {
        super(ConversationScoped.class);
        setParentContext(parentContext);
    }

    @Override
    protected Contextual lookupContext(final String bindingName) {
        if (CONVERSATION_CONTEXT_NAME.equals(bindingName)) {
            return bind(bindingName, this);
        }

        return super.lookupContext(bindingName);
    }

    @Override
    public void dispatchRoute(final String aRoute) {
        dispatchRoute(aRoute, null);
    }

    @Override
    public void dispatchRoute(final String aRoute, final RouteDispatchedCallback aRouteDispatchedCallback) {
        loadRouteFactory();
        loadMessageService();

        final RouteMessage routeMessage = routeFactory.createRouteMessage(aRoute);
        bindRoute(routeMessage.getRoute());

        messageService.getQueue("org.weaveframework.routing").sendMessage(routeMessage,
            createRouteDispatchedMessageCallback(aRouteDispatchedCallback));
    }

    private void bindRoute(final Object aRoute) {
        bind(Route.class.getName(), aRoute);
    }

    private void loadRouteFactory() {
        if (routeFactory == null) {
            routeFactory = lookup(RouteFactory.class);
        }
    }

    private void loadMessageService() {
        if (messageService == null) {
            messageService = lookup(MessageService.class);
        }
    }

    private MessageCallback createRouteDispatchedMessageCallback(final RouteDispatchedCallback aRouteDispatchedCallback) {
        if (aRouteDispatchedCallback == null) {
            return null;
        }

        return new MessageCallback() {
            @Override
            public void onComplete(final MessageResult aMessageResult) {
                aRouteDispatchedCallback.executeCallback(aMessageResult.getResult());
            }
        };
    }

    @Override
    public void dispatchFeed(final String aFeedName, final String aFeedValue) {
        dispatchFeed(aFeedName, aFeedValue, null);
    }

    @Override
    public void dispatchFeed(final String aFeedName, final String aFeedValue,
        final FeedDispatchedCallback aFeedDispatchedCallback) {
        loadFeedFactory();

        feedFactory.dispatchFeed(aFeedName, aFeedValue, createFeedDispatchedMessageCallback(aFeedDispatchedCallback));
    }

    private void loadFeedFactory() {
        if (feedFactory == null) {
            feedFactory = lookup(FeedFactory.class);
        }
    }

    private MessageCallback createFeedDispatchedMessageCallback(final FeedDispatchedCallback aFeedDispatchedCallback) {
        if (aFeedDispatchedCallback == null) {
            return null;
        }

        return new MessageCallback() {
            @Override
            public void onComplete(final MessageResult aMessageResult) {
                aFeedDispatchedCallback.executeCallback(aMessageResult.getResult());
            }
        };
    }
}
